// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

#include <QvisPostableWindowSimpleObserver.h>
#include <QLayout>
#include <QMessageBox>
#include <QPushButton>
#include <QToolButton>
#include <QScrollArea>

#include <GlobalAttributes.h>
#include <ViewerProxy.h>

// Static members.
const int QvisPostableWindowSimpleObserver::NoExtraButtons    = 0;
const int QvisPostableWindowSimpleObserver::ApplyButton       = 1;
const int QvisPostableWindowSimpleObserver::MakeDefaultButton = 2;
const int QvisPostableWindowSimpleObserver::ResetButton       = 4;
const int QvisPostableWindowSimpleObserver::AllExtraButtons   = 7;

const int QvisPostableWindowSimpleObserver::LoadButton                 = 8;
const int QvisPostableWindowSimpleObserver::SaveButton                 = 16;
const int QvisPostableWindowSimpleObserver::AllExtraButtonsAndLoadSave = 31;

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::QvisPostableWindowSimpleObserver
//
// Purpose: 
//   Constructor for the QvisPostableWindowSimpleObserver class.
//
// Arguments:
//   caption   : The window caption.
//   shortName : The name used when the window is posted.
//   notepad   : The notepad area into which the window posts.
//
// Programmer: Brad Whitlock
// Creation:   Mon Aug 27 12:39:44 PDT 2001
//
// Modifications:
//   Jeremy Meredith, Wed May  8 10:51:09 PDT 2002
//   Added stretch flag.
//
//   Brad Whitlock, Mon Sep 9 11:00:03 PDT 2002
//   Added applyButton flag.
//
//   Brad Whitlock, Wed Apr  9 10:49:15 PDT 2008
//   QString for caption and shortName.
//
// ****************************************************************************

QvisPostableWindowSimpleObserver::QvisPostableWindowSimpleObserver(
    const QString &caption, const QString &shortName, QvisNotepadArea *notepad,
    int buttonCombo, bool stretch) :
    QvisPostableWindow(caption, shortName, notepad), SimpleObserver()
{
    selectedSubject = 0;
    stretchWindow = stretch;
    buttonCombination = buttonCombo;
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::~QvisPostableWindowSimpleObserver
//
// Purpose: 
//   Destructor for the QvisPostableWindowSimpleObserver class.
//
// Programmer: Brad Whitlock
// Creation:   Mon Aug 27 12:40:40 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

QvisPostableWindowSimpleObserver::~QvisPostableWindowSimpleObserver()
{
    // nothing here.
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::Update
//
// Purpose: 
//   This method is called when the window's subjects are modified.
//
// Arguments:
//   subj : A pointer to the subject that was modified.
//
// Programmer: Brad Whitlock
// Creation:   Mon Aug 27 12:40:58 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::Update(Subject *subj)
{
    // This is what derived types will query to determine which subject
    // was modified.
    selectedSubject = subj;

    if(isCreated)
        UpdateWindow(false);
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::SubjectRemoved
//
// Purpose: 
//   This method is called when a subject is deleted.
//
// Programmer: Brad Whitlock
// Creation:   Mon Aug 27 12:41:39 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::SubjectRemoved(Subject *TheRemovedSubject)
{
    // nothing here.
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::SelectedSubject
//
// Purpose: 
//   Returns which subject is currently being updated.
//
// Programmer: Brad Whitlock
// Creation:   Mon Aug 27 12:42:10 PDT 2001
//
// Modifications:
//   
// ****************************************************************************

Subject *
QvisPostableWindowSimpleObserver::SelectedSubject()
{
    return selectedSubject;
}

// ****************************************************************************
// Method: QvisPostableWindow::CreateEntireWindow
//
// Purpose: 
//   Creates the widgets for the window.
//
// Programmer: Brad Whitlock
// Creation:   Mon Aug 27 12:36:50 PDT 2001
//
// Modifications:
//   Brad Whitlock, Fri Feb 15 11:27:15 PDT 2002
//   Added code to return if the window is already created.
//
//   Jeremy Meredith, Wed May  8 10:50:54 PDT 2002
//   Only add stretch if the stretchWindow flag is set.
//
//   Brad Whitlock, Mon Sep 9 11:01:00 PDT 2002
//   I made the apply button optional.
//
//   Brad Whitlock, Fri Nov 7 16:48:36 PST 2003
//   Added support for more buttons.
//
//   Brad Whitlock, Mon Nov 14 10:36:48 PDT 2005
//   Disable post button if posting is not enabled.
//
//   Brad Whitlock, Tue Jan 22 16:45:13 PST 2008
//   If posting is disabled, put the contents of the window into a scrollview.
//
//   Brad Whitlock, Tue Apr  8 15:26:49 PDT 2008
//   Support for internationalization.
//
//   Brad Whitlock, Fri Jun  6 10:50:39 PDT 2008
//   Qt 4.
//
//   Jeremy Meredith, Fri Jan  2 17:05:57 EST 2009
//   Added Load/Save button support.  Put them in between the
//   Make Default and Reset buttons for now.
//
//   Eddie Rusu, Thu Jan 21 09:48:44 PST 2021
//   Set the FocusPolicy for the ApplyButton to StrongFocus so that when the
//   button is clicked, the focus shifts from any other widges to the Apply
//   button, triggering any value change on the previously focused widget.
//
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::CreateEntireWindow()
{
    // If the window is already created, return.
    if(isCreated)
        return;

    // Create the central widget and the top layout.
    QWidget *topCentral = 0;
    QVBoxLayout *vLayout = 0;
    if(notepad)
    {
        central = new QWidget( this );
        setCentralWidget( central );
        topCentral = central;
        topLayout = new QVBoxLayout(central);
        topLayout->setContentsMargins(10,10,10,10);
        vLayout = topLayout;
    }
    else
    {
        topCentral = new QWidget(this);
        vLayout = new QVBoxLayout(topCentral);
        vLayout->setContentsMargins(10,10,10,10);
        vLayout->setSpacing(5);
        setCentralWidget( topCentral );
        
        QScrollArea *sv = new QScrollArea(topCentral);
        sv->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
        sv->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
        sv->setWidgetResizable(true);
        central = new QWidget(0);
        sv->setWidget(central);
        vLayout->addWidget(sv);
        topLayout = new QVBoxLayout(central);
        topLayout->setContentsMargins(10,10,10,10);
    }

    // Call the Sub-class's CreateWindowContents function to create the
    // internal parts of the window.
    CreateWindowContents();

    // Create a button layout and the buttons.
    vLayout->addSpacing(10);
    QGridLayout *buttonLayout = new QGridLayout(0);
    vLayout->addLayout(buttonLayout);
    buttonLayout->setColumnStretch(1, 50);

    // Create the extra buttons if necessary.
    if(buttonCombination & MakeDefaultButton)
    {
        QPushButton *makeDefaultButton = new QPushButton(tr("Make default"),
            topCentral);
        connect(makeDefaultButton, SIGNAL(clicked()),
                this, SLOT(makeDefaultHelper()));
        buttonLayout->addWidget(makeDefaultButton, 0, 0);
    }
    if(buttonCombination & ResetButton)
    {
        QPushButton *resetButton = new QPushButton(tr("Reset"), topCentral);
        connect(resetButton, SIGNAL(clicked()), this, SLOT(reset()));
        buttonLayout->addWidget(resetButton, 0, 4);
    }

    if(buttonCombination & LoadButton)
    {
        QPushButton *loadButton = new QPushButton(tr("Load"),
            topCentral);
        connect(loadButton, SIGNAL(clicked()), this, SLOT(loadSubject()));
        buttonLayout->addWidget(loadButton, 0, 2);
    }
    if(buttonCombination & SaveButton)
    {
        QPushButton *saveButton = new QPushButton(tr("Save"), topCentral);
        connect(saveButton, SIGNAL(clicked()), this, SLOT(saveSubject()));
        buttonLayout->addWidget(saveButton, 0, 3);
    }

    if(buttonCombination & ApplyButton)
    {
        QPushButton *applyButton = new QPushButton(tr("Apply"), topCentral);
        applyButton->setFocusPolicy(Qt::StrongFocus);
        connect(applyButton, SIGNAL(clicked()), this, SLOT(apply()));
        buttonLayout->addWidget(applyButton, 1, 0);
    }
    else
    {
        // Add a little space to try and make up for the absence of the
        // grid layout.
        buttonLayout->setColumnStretch(1, 50);
    }
    QPushButton *helpButton = new QPushButton(topCentral);
    helpButton->setVisible(false);
    helpButton->setText(tr("?"));
    connect(helpButton, SIGNAL(clicked()), this, SLOT(help()));
    buttonLayout->addWidget(helpButton, 1, 2);

    postButton = new QPushButton(tr("Post"), topCentral);
    // Make the window post itself when the post button is clicked.
    if(notepad)
    {
        connect(postButton, SIGNAL(clicked()), this, SLOT(post()));
        postButton->setEnabled(postEnabled);
    }
    else
        postButton->setEnabled(false);
    buttonLayout->addWidget(postButton, 1, 3);
    QPushButton *dismissButton = new QPushButton(tr("Dismiss"), topCentral);
    connect(dismissButton, SIGNAL(clicked()), this, SLOT(hide()));
    buttonLayout->addWidget(dismissButton, 1, 4);


    if(notepad != 0 && stretchWindow)
        vLayout->addStretch(0);

    // Set the isCreated flag.
    isCreated = true;
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::apply
//
// Purpose: 
//   This is a Qt slot function that is called when the Apply button is clicked.
//
// Programmer: Brad Whitlock
// Creation:   Fri Nov 7 16:56:08 PST 2003
//
// Modifications:
//   
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::apply()
{
    // override in derived class.
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::makeDefaultHelper
//
// Purpose: 
//   This is a Qt slot function that calls the makeDefault() slot after
//   optionally displaying a confirmation dialog box.
//
// Programmer: Brad Whitlock
// Creation:   Thu Aug 23 8:31:23 PDT 2001
//
// Modifications:
//   Brad Whitlock, Mon Aug 27 11:17:21 PDT 2001
//   I changed the behavior of the third button in the confirmation window.
//
//   Brad Whitlock, Mon Nov 4 14:11:22 PST 2002
//   I made it so the "make default" behavior can be turned off permanently.
//
//   Brad Whitlock, Tue Apr  8 15:26:49 PDT 2008
//   Support for internationalization.
//
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::makeDefaultHelper()
{
    if(makeDefaultConfirm)
    {
        QString msg(tr("Do you really want to make these the default attributes?"));

        // Ask the user if he really wants to set the defaults
        int button = QMessageBox::warning(0, "VisIt", msg, tr("Ok"), tr("Cancel"),
                                          tr("Yes, Do not prompt again"), 0, 1);

        if(button == 0)
        {
            // The user actually chose to set the defaults.
            makeDefault();
        }
        else if(button == 2)
        {
            // Make it so no confirmation is needed.
            makeDefaultConfirm = false;
            GlobalAttributes *globalAtts = GetViewerState()->GetGlobalAttributes();
            globalAtts->SetMakeDefaultConfirm(false);
            globalAtts->Notify();

            makeDefault();
        }
    }
    else
        makeDefault();
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::makeDefault
//
// Purpose: 
//   Causes the current attributes to be copied into the default
//   attributes. This should be overridden in derived classes.
//
// Programmer: Brad Whitlock
// Creation:   Fri Sep 15 13:40:19 PST 2000
//
// Modifications:
//   
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::makeDefault()
{
    // override in derived class.
}

// ****************************************************************************
// Method: QvisPostableWindowSimpleObserver::reset
//
// Purpose: 
//   Causes the last applied attributes to be restored. This will
//   result in the window's UpdateWindow method being called to
//   update the window's widgets.
//
// Programmer: Brad Whitlock
// Creation:   Fri Sep 15 13:40:19 PST 2000
//
// Modifications:
//   
// ****************************************************************************

void
QvisPostableWindowSimpleObserver::reset()
{
    // override in derived class.
}

// ****************************************************************************
//  Method:  QvisPostableWindowSimpleObserver::loadSubject
//
//  Purpose:
//    Load the window's subject from a file.  This is empty
//    because this derived class doesn't have a sole subject.
//
//  Arguments:
//    none
//
//  Programmer:  Jeremy Meredith
//  Creation:    January  2, 2009
//
// ****************************************************************************
void
QvisPostableWindowSimpleObserver::loadSubject()
{
    // override in derived class.
}

// ****************************************************************************
//  Method:  QvisPostableWindowSimpleObserver::saveSubject
//
//  Purpose:
//    Save the window's subject to a file.  This is empty
//    because this derived class doesn't have a sole subject.
//
//  Arguments:
//    none
//
//  Programmer:  Jeremy Meredith
//  Creation:    January  2, 2009
//
// ****************************************************************************
void
QvisPostableWindowSimpleObserver::saveSubject()
{
    // override in derived class.
}

